#ifndef __HDVB_SECTION_H
#define __HDVB_SECTION_H
/*
    libhdvbd - Library for building sophisticated DVB applications
    Copyright (C) 2012 Tony Houghton <h@realh.co.uk>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/* Data structures etc representing various types of TS section */

#include <glib.h>

#include <hdvb/dvbenc.h>

G_BEGIN_DECLS

#ifndef HDVB_UNKNOWN_SIZE
#define HDVB_UNKNOWN_SIZE 1
#endif

#define HDVB_PID_PAT   0x00
#define HDVB_PID_CAT   0x01
#define HDVB_PID_TSDT  0x02
#define HDVB_PID_NIT   0x10
#define HDVB_PID_SDT   0x11
#define HDVB_PID_BAT   0x11
#define HDVB_PID_EIT   0x12
#define HDVB_PID_RST   0x13
#define HDVB_PID_TDT   0x14
#define HDVB_PID_TOT   0x14
#define HDVB_PID_RNT   0x16
#define HDVB_PID_DIT   0x1E
#define HDVB_PID_SIT   0x1F
#define HDVB_PID_FS_NIT    3840
#define HDVB_PID_FS_BAT    3841
#define HDVB_PID_FS_SDT    3841
#define HDVB_PID_FS_EIT_S  3842
#define HDVB_PID_FS_EIT_PF 3843
#define HDVB_PID_FS_TDT    3844
#define HDVB_PID_FS_TOT    3844

#define HDVB_TAB_PAT                   0x00
#define HDVB_TAB_CAT                   0x01
#define HDVB_TAB_PMT                   0x02
#define HDVB_TAB_TSDT                  0x03
#define HDVB_TAB_NIT                   0x40
#define HDVB_TAB_NIT_OTHER             0x41
#define HDVB_TAB_SDT                   0x42
#define HDVB_TAB_SDT_OTHER             0x46
#define HDVB_TAB_BAT                   0x4A
#define HDVB_TAB_EIT_PF                0x4E
#define HDVB_TAB_EIT_OTHER_PF          0x4F
#define HDVB_TAB_EIT_SCHEDULE          0x50
#define HDVB_TAB_EIT_OTHER_SCHEDULE    0x60
#define HDVB_TAB_TDT                   0x70
#define HDVB_TAB_RST                   0x71
#define HDVB_TAB_ST                    0x72
#define HDVB_TAB_TOT                   0x73
#define HDVB_TAB_FS_EIT_PF             0xD1

#define HDVB_TABLE_ID_IS_EIT(t) (((t) >= 0x4e && (t) <= 0x6f) || \
        (t) == HDVB_TAB_FS_EIT_PF)

#define HDVB_DTAG_ISO639_LANGUAGE      0x0A
#define HDVB_DTAG_SATELLITE_DELIVERY   0x43
#define HDVB_DTAG_SERVICE              0x48
#define HDVB_DTAG_SHORT_EVENT          0x4D
#define HDVB_DTAG_TIME_SHIFTED_EVENT   0x4F
#define HDVB_DTAG_STREAM_IDENTIFIER    0x52
#define HDVB_DTAG_TELETEXT             0x56
#define HDVB_DTAG_SUBTITLING           0x59
#define HDVB_DTAG_TERRESTRIAL_DELIVERY 0x5A
#define HDVB_DTAG_AC3                  0x6A
#define HDVB_DTAG_ENHANCED_AC3         0x7A
#define HDVB_DTAG_DTS                  0x7B
#define HDVB_DTAG_AAC                  0x7C
#define HDVB_DTAG_EXTENSION            0x7F

#define HDVB_DEXT_T2_DELIVERY          0x04
#define HDVB_DEXT_REGION               0x09
#define HDVB_DEXT_REGION_NAME          0x0A

/* Use arrays of bytes instead of 16-bit words for endianness portability */
typedef struct {
    guint8 table_id;
    guint8 section_length[2];   /* Only 12 LSB are length */
    guint8 section_id[2];       /* Purpose varies depending on section type */
    guint8 version_number;
    guint8 section_number;
    guint8 last_section_number;
} HdvbSectionHeader;

typedef struct {
    guint8 table_id;
    guint8 section_length[2];   /* Only 12 LSB are length */
} HdvbSectionShortHeader;

typedef struct {
    HdvbSectionHeader h;
    guint8 d[1024 - sizeof(HdvbSectionHeader)];
    /* Last 4 bytes are CRC, but not much point in including that in struct
     * because actual position varies */
} HdvbSection;

/* A section should be allocated with g_slice_alloc, 1024 bytes for most
 * sections, 4096 for EIT. hdvb_section_free should only be used when the
 * section contains a valid table_id, otherwise keep track of its size yourself.
 */
inline static void
hdvb_section_free(HdvbSection *sec)
{
    if (sec)
        g_slice_free1(HDVB_TABLE_ID_IS_EIT(sec->h.table_id) ? 4096 : 1024, sec);
}

#define HDVB_MAKE_WORD16(a) ((((guint) *(a)) << 8) | *((a) + 1))
#define HDVB_MAKE_WORD32(a) ((((guint) *(a)) << 24) | \
        (((guint) *((a) + 1)) << 16) | (((guint) *((a) + 2)) << 8) | *((a) + 3))

#define HDVB_12BITS(w) ((w) & 0xfff)

#define HDVB_MAKE_12BITS(a) HDVB_12BITS(HDVB_MAKE_WORD16(a))
#define HDVB_MAKE_WORD12 HDVB_MAKE_12BITS

#define HDVB_BCD16(a) \
        ((guint) hdvb_bcd8(*(a)) * 100 + (guint) hdvb_bcd8(*((a) + 1)))

#define HDVB_BCD24(a) ((guint) hdvb_bcd8(*(a)) * 10000 + \
        (guint) hdvb_bcd8(*((a) + 1)) * 100 + \
        (guint) hdvb_bcd8(*((a) + 2)))

#define HDVB_BCD32(a) ((guint) hdvb_bcd8(*(a)) * 1000000 + \
        (guint) hdvb_bcd8(*((a) + 1)) * 10000 + \
        (guint) hdvb_bcd8(*((a) + 2)) * 100 + \
        (guint) hdvb_bcd8(*((a) + 3)))

#define HDVB_BCD_TIME(a) ((guint) hdvb_bcd8(*(a)) * 3600 + \
        (guint) hdvb_bcd8(*((a) + 1)) * 60 + \
        (guint) hdvb_bcd8(*((a) + 2)))
 

/* This includes 5 further bytes of header and 4 CRC,
 * so HDVB_SECTION_DATA_LENGTH is usually more useful
 */
#define HDVB_SECTION_LENGTH(s) \
        HDVB_12BITS(HDVB_MAKE_WORD16((s)->h.section_length))

#define HDVB_SECTION_DATA_LENGTH(s) (HDVB_SECTION_LENGTH(s) - 9)

#define HDVB_SECTION_VERSION(s) (((s)->h.version_number >> 1) & 0x1f)

#define HDVB_SECTION_CURRENT_NEXT(s) ((s)->h.version_number & 1)

#define HDVB_SECTION_ID(s) HDVB_MAKE_WORD16((s)->h.section_id)

#define HDVB_SECTION_WORD(s, i) HDVB_MAKE_WORD16((s)->d + i)

#define HDVB_SECTION_12BITS(s, i) HDVB_MAKE_12BITS((s)->d + i)


/* The following list_..._info and list_..._descriptors all return lists
 * whose items' data point to within the raw section data, so do not free
 * the data, but do g_list_free() the lists. They return data in reverse order
 * to how it appears in sections because g_list_prepend is more efficient
 * than append.
 */

/**************************************/

/* PAT */

#define HDVB_SECTION_PAT_TRANSPORT_ID(s) HDVB_SECTION_ID(s)

/* PMT */

#define HDVB_SECTION_PMT_SERVICE_ID(s) HDVB_SECTION_ID(s)
#define HDVB_SECTION_PMT_PCR(s) (HDVB_SECTION_WORD((s), 0) & 0x1fff)

typedef struct {
    guint8 stream_type;
    guint8 pid[2];                      /* 13 bits LSB only */
    guint8 descriptors_length[2];       /* 12 bits LSB only */
    guint8 descriptors[HDVB_UNKNOWN_SIZE];
} HdvbPMTStreamInfo;

#define HDVB_SECTION_PMT_STREAM_INFO_PID(si) \
        (HDVB_MAKE_WORD16((si)->pid) & 0x1fff)
#define HDVB_SECTION_PMT_STREAM_INFO_DESCRIPTORS_LENGTH(si) \
        HDVB_MAKE_12BITS((si)->descriptors_length)

GList *
hdvb_section_list_pmt_info(const HdvbSection *sec);

GList *
hdvb_section_list_pmt_stream_info_descriptors(const HdvbPMTStreamInfo *si);

/**************************************/

/* SDT */

#define HDVB_SECTION_SDT_TS_ID(s) HDVB_SECTION_ID(s)
#define HDVB_SECTION_SDT_NETWORK_ID(s) HDVB_SECTION_WORD((s), 0)

typedef struct {
    guint8 service_id[2];
    guint8 eit_flags;
    guint8 descriptors_length[2];  /* Also contains running_status and
                                         * free_CA_mode */
    guint8 descriptors[HDVB_UNKNOWN_SIZE];
} HdvbSDTInfo;

#define HDVB_SECTION_SDT_INFO_EIT_SCHEDULE(si) (((si)->eit_flags >> 1) & 1)
#define HDVB_SECTION_SDT_INFO_EIT_PF(si) ((si)->eit_flags & 1)
#define HDVB_SECTION_SDT_INFO_RUNNING_STATUS(si) \
        (((si)->descriptors_length[0] >> 5) & 7)
#define HDVB_SECTION_SDT_INFO_FREE_CA_MODE(si) \
        (((si)->descriptors_length[0] >> 4) & 1)
#define HDVB_SECTION_SDT_INFO_DESCRIPTORS_LENGTH(si) \
        HDVB_MAKE_12BITS((si)->descriptors_length)

GList *
hdvb_section_list_sdt_info(const HdvbSection *sec);

GList *
hdvb_section_list_sdt_info_descriptors(const HdvbSDTInfo *si);

/**************************************/

/* Common to NIT and BAT */

typedef struct {
    guint8 ts_id[2];
    guint8 network_id[2];
    guint8 descriptors_length[2];
    guint8 descriptors[HDVB_UNKNOWN_SIZE];
} HdvbTransportInfo;

GList *
hdvb_section_list_transport_info(const HdvbSection *sec);

#define HDVB_SECTION_TRANSPORT_INFO_DESCRIPTORS_LENGTH(ni) \
        HDVB_MAKE_12BITS((ni)->descriptors_length)

GList *
hdvb_section_list_transport_info_descriptors(const HdvbTransportInfo *ni);

/**************************************/

/* NIT */

#define HDVB_SECTION_NIT_NETWORK_ID(sec) HDVB_SECTION_ID(s)

GList *
hdvb_section_list_nit_descriptors(HdvbSection *sec);

/**************************************/

/* BAT */

#define HDVB_SECTION_BAT_BOUQUET_ID(s) HDVB_SECTION_ID(s)

GList *
hdvb_section_list_bouquet_descriptors(const HdvbSection *sec);

typedef struct {
    guint8 ts_id[2];
    guint8 network_id[2];
    guint8 descriptors_length[2];   /* 12 bits */
    guint8 descriptors[HDVB_UNKNOWN_SIZE];
} HdvbBATInfo;

/**************************************/

/* EIT */

typedef struct {
    HdvbSectionHeader h;
    guint8 ts_id[2];
    guint8 network_id[2];
    guint8 segment_last_section_number;
    guint8 last_table_id;
    guint8 info[HDVB_UNKNOWN_SIZE];
} HdvbEitSection;

#define HDVB_EIT_SECTION_SERVICE_ID(s) HDVB_SECTION_ID(s)
#define HDVB_EIT_SECTION_TS_ID(s) HDVB_MAKE_WORD16((s)->ts_id)
#define HDVB_EIT_SECTION_NETWORK_ID(s) HDVB_MAKE_WORD16((s)->network_id)

typedef struct {
    guint8 event_id[2];
    guint8 start_time_mjd[2];
    guint8 start_time_hms[3];       /* HHMMSS BCD */
    guint8 duration[3];             /* HHMMSS BCD */
    guint8 descriptors_length[2];   /* First 4 bits are running status and CA */
    guint8 descriptors[HDVB_UNKNOWN_SIZE];
} HdvbEitInfo;

#define HDVB_EIT_INFO_EVENT_ID(i) HDVB_MAKE_WORD16((i)->event_id)
#define HDVB_EIT_INFO_RUNNING_STATUS(i) \
        (((i)->descriptors_length[0] & 0xe0) >> 5)
#define HDVB_EIT_INFO_FREE_CA_MODE(i) (((i)->descriptors_length[0] & 0x10) >> 4)
#define HDVB_EIT_INFO_DESCRIPTORS_LENGTH(i) \
        HDVB_MAKE_12BITS((i)->descriptors_length)

/* Returns list of const HdvbEitInfo * */
GList *
hdvb_section_list_eit_info(const HdvbEitSection *sec);

/* Returns list of const HdvbDescriptor * */
GList *
hdvb_section_list_eit_info_descriptors(const HdvbEitInfo *info);

/**************************************/

/* RST */

#define HDVB_SECTION_RUNNING_STATUS_NOT_RUNNING    1
#define HDVB_SECTION_RUNNING_STATUS_STARTS_SOON    2
#define HDVB_SECTION_RUNNING_STATUS_PAUSED         3
#define HDVB_SECTION_RUNNING_STATUS_RUNNING        4
#define HDVB_SECTION_RUNNING_STATUS_OFF_AIR        5

typedef struct {
    guint8 ts_id[2];
    guint8 network_id[2];
    guint8 service_id[2];
    guint8 event_id[2];
    guint8 running_status;  /* Ignore top 5 bits */
} HdvbRstInfo;

#define HDVB_SECTION_RST_INFO_GET_STATUS(i) ((i)->running_status & 7)

typedef struct {
    HdvbSectionShortHeader h;
    HdvbRstInfo d[HDVB_UNKNOWN_SIZE];
} HdvbRstSection;

/* Returns list of const HdvbRstInfo * */
GList *
hdvb_section_list_rst_info(const HdvbRstSection *sec);


/*************************************************************************/

/* Descriptors */

typedef struct {
    guint8 tag;
    guint8 length;
} HdvbDescriptorHeader;

typedef struct {
    HdvbDescriptorHeader h;
    guint8 d[HDVB_UNKNOWN_SIZE];
} HdvbDescriptor;

typedef struct {
    HdvbDescriptorHeader h;
    guint8 component_tag;
} HdvbStreamIdentifierDescriptor;

typedef struct {
    HdvbDescriptorHeader h;
    struct {
        char iso_639_language_code[3];
        guint8 audio_type;
    } d[1];
} HISO639LanguageDescriptor;

typedef struct {
    HdvbDescriptorHeader h;
    struct {
        char iso_639_language_code[3];
        guint8 subtitling_type;
        guint8 composition_page_id[2];
        guint8 ancillary_page_id[2];
    } d[1];
} HdvbSubtitlingDescriptor;

typedef struct {
    HdvbDescriptorHeader h;
    struct {
        char iso_639_language_code[3];
        guint8 teletext_type;   /* Also includes magazine number */
        guint8 teletext_page_number;
    } d[1];
} HdvbTeletextDescriptor;

#define HDVB_TELETEXT_DESCRIPTOR_TYPE(desc, n) ((desc)->d[n].teletext_type >> 3)
#define HDVB_TELETEXT_DESCRIPTOR_MAGAZINE_NUMBER(d, n) \
        ((d)->d[n].teletext_type & 7)

/* Service descriptor */

#define HDVB_SERVICE_DESCRIPTOR_SERVICE_TYPE(desc) ((desc)->d[0])

/* Start of string, including leading encoding byte,
 * is stored in *s, length in *l
 */
inline static void
hdvb_service_descriptor_provider_name(const HdvbDescriptor *d,
        guint8 const **s, int *l)
{
    *s = d->d + 2;
    *l = d->d[1];
}

inline static void
hdvb_service_descriptor_service_name(const HdvbDescriptor *d,
        guint8 const **s, int *l)
{
    int l1 = d->d[1];
    *s = d->d + 3 + l1;
    *l = d->d[2 + l1];
}


/* Satellite delivery descriptor */

typedef struct {
    HdvbDescriptorHeader h;
    guint8 frequency[4];
    guint8 orbital_pos[2];  /* BCD */
    guint8 flags;
    guint8 symbol_rate[4];  /* 28 msbits symbol_rate BCD, 4 lsbits FEC_inner */
} HdvbSatelliteDeliveryDescriptor;

#define HDVB_SATELLITE_DELIVERY_DESCRIPTOR_FREQUENCY(desc) \
        (HDVB_BCD32((desc)->frequency) * 10)   /* KHz */

#define HDVB_SATELLITE_DELIVERY_DESCRIPTOR_ORBITAL_POSITION(desc) \
        HDVB_BCD16((desc)->orbital_pos)        /* divide result by 10 */

#define HDVB_SATELLITE_DELIVERY_DESCRIPTOR_WEST_EAST(desc) \
        (((desc)->flags & 0x80) >> 7)

#define HDVB_SATELLITE_DELIVERY_DESCRIPTOR_POLARIZATION(desc) \
        (((desc)->flags & 0x60) >> 5)

#define HDVB_SATELLITE_DELIVERY_DESCRIPTOR_ROLL_OFF(desc) \
        (((desc)->flags & 0x18) >> 3)

#define HDVB_SATELLITE_DELIVERY_DESCRIPTOR_MODULATION_SYSTEM(desc) \
        (((desc)->flags & 0x4) >> 2)

#define HDVB_SATELLITE_DELIVERY_DESCRIPTOR_MODULATION_TYPE(desc) \
        (desc->flags & 0x3)

#define HDVB_SATELLITE_DELIVERY_DESCRIPTOR_SYMBOL_RATE(desc) \
        ((guint) hdvb_bcd8((desc)->symbol_rate[0]) * 10000000 + \
        (guint) hdvb_bcd8((desc)->symbol_rate[1]) * 100000 + \
        (guint) hdvb_bcd8((desc)->symbol_rate[2]) * 1000 + \
        (guint) hdvb_bcd8((desc)->symbol_rate[3] >> 4) * 100)

#define HDVB_SATELLITE_DELIVERY_DESCRIPTOR_FEC_INNER(desc) \
        ((desc)->symbol_rate[3] & 0xf)


/* Terrestrial delivery descriptor.
 * It's split up into so many bitfields it isn't really worth defining a
 * struct for.
 */

typedef HdvbDescriptor HdvbTerrestrialDeliveryDescriptor;

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_FREQUENCY(desc) \
        (HDVB_MAKE_WORD32((desc)->d) * 10)   /* Hz */

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_BANDWIDTH(desc) \
        ((desc)->d[4] >> 5)

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_PRIORITY(desc) \
        (((desc)->d[4] & 0x10) >> 4)

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_TIME_SLICING(desc) \
        (((desc)->d[4] & 0x8) >> 3)

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_MPE_FEC(desc) \
        (((desc)->d[4] & 0x4) >> 2)

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_CONSTELLATION(desc) \
        (((desc)->d[5] & 0xc0) >> 6)

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_HIERARCHY(desc) \
        (((desc)->d[5] & 0x38) >> 3)

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_CODE_RATE_HP(desc) \
        ((desc)->d[5] & 0x7)

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_CODE_RATE_LP(desc) \
        (((desc)->d[6] & 0xe0) >> 5)

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_GUARD_INTERVAL(desc) \
        (((desc)->d[6] & 0x18) >> 3)

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_TRANSMISSION_MODE(desc) \
        (((desc)->d[6] & 0x6) >> 1)

#define HDVB_TERRESTRIAL_DELIVERY_DESCRIPTOR_OTHER_FREQUENCY_FLAG(desc) \
        ((desc)->d[6] & 0x1)


/* EIT descriptors */

/* Short event descriptor */

typedef struct {
    HdvbDescriptorHeader h;
    char ISO_639_language_code[3];
    guint8 event_name_length;
    guint8 event_name[HDVB_UNKNOWN_SIZE];  /* Not char because it's encoded */
} HdvbShortEventDescriptor;

#define HDVB_SHORT_EVENT_DESCRIPTOR_TEXT_LENGTH(d) \
        ((d)->event_name[(d)->event_name_length])
#define HDVB_SHORT_EVENT_DESCRIPTOR_TEXT(d) \
        ((d)->event_name + (d)->event_name_length + 1)

/* Time shifted event */

typedef struct {
    HdvbDescriptorHeader h;
    guint8 reference_service_id[2];
    guint8 reference_event_id[2];
} HdvbTimeShiftedEventDescriptor;


/*************** Extension descriptors *****************/

typedef struct {
    HdvbDescriptorHeader h;
    guint8 tag_extension;
    guint8 data[HDVB_UNKNOWN_SIZE];
} HdvbExtensionDescriptor;

/* Target region descriptor */

typedef struct {
    HdvbDescriptorHeader h;
    guint8 tag_extension;
    char country_code[3];
    guint8 region_data[HDVB_UNKNOWN_SIZE];
} HdvbTargetRegionDescriptor;

/* Returns a list of const guint8 * */
GList *
hdvb_target_region_descriptor_list_regions(const HdvbTargetRegionDescriptor *);

#define HDVB_REGION_DATA_COUNTRY_CODE_FLAG(d) ((d[0] & 4) >> 2)
#define HDVB_REGION_DATA_REGION_DEPTH(d) (d[0] & 3)
#define HDVB_REGION_DATA_COUNTRY_CODE(d) (d + 1)
#define HDVB_REGION_DATA_REGION_ADDR(d) \
        (d + (HDVB_REGION_DATA_COUNTRY_CODE_FLAG(d) ? 4 : 1))
#define HDVB_REGION_DATA_PRIMARY_CODE(d) \
        (HDVB_REGION_DATA_REGION_ADDR(d)[0])
#define HDVB_REGION_DATA_SECONDARY_CODE(d) \
        (HDVB_REGION_DATA_REGION_ADDR(d)[1])
#define HDVB_REGION_DATA_TERTIARY_CODE(d) \
        HDVB_MAKE_WORD16(HDVB_REGION_DATA_REGION_ADDR(d) + 2)

/* Target region name descriptor */

typedef struct {
    HdvbDescriptorHeader h;
    guint8 tag_extension;
    char country_code[3];
    char lang[3];
    guint8 region_data[HDVB_UNKNOWN_SIZE];
} HdvbTargetRegionNameDescriptor;

/* Returns a list of const guint8 * */
GList *
hdvb_target_region_name_descriptor_list_regions(
        const HdvbTargetRegionNameDescriptor *);

#define HDVB_REGION_NAME_DATA_REGION_DEPTH(d) (d[0] >> 6)
#define HDVB_REGION_NAME_DATA_NAME_LENGTH(d)  (d[0] & 0x3f)
#define HDVB_REGION_NAME_DATA_PRIMARY_CODE(d) \
        (d[HDVB_REGION_NAME_DATA_NAME_LENGTH(d) + 1])
#define HDVB_REGION_NAME_DATA_SECONDARY_CODE(d) \
        (d[HDVB_REGION_NAME_DATA_NAME_LENGTH(d) + 2])
#define HDVB_REGION_NAME_DATA_TERTIARY_CODE(d) \
        HDVB_MAKE_WORD16(HDVB_REGION_NAME_DATA_NAME_LENGTH(d) + 3)

/* DVB-T2 delivery system */

typedef HdvbExtensionDescriptor HdvbT2DeliveryDescriptor;

#define HDVB_T2_DELIVERY_SISO_MISO(b) (((b) & 0xc0) >> 6)
#define HDVB_T2_DELIVERY_BANDWIDTH(b) (((b) & 0x3c) >> 2)
#define HDVB_T2_DELIVERY_GUARD_INTERVAL(b) (((b) & 0xe0) >> 5)
#define HDVB_T2_DELIVERY_TRANSMISSION_MODE(b) (((b) & 0x1c) >> 2)
#define HDVB_T2_DELIVERY_OTHER_FREQUENCY(b) (((b) & 0x02) >> 1)
#define HDVB_T2_DELIVERY_TFS(b) ((b) & 0x01)

#define HDVB_T2_DELIVERY_DESCRIPTOR_PLP_ID(d) \
        ((d)->data[0])
#define HDVB_T2_DELIVERY_DESCRIPTOR_SYSTEM_ID(d) \
        HDVB_MAKE_WORD16((d)->data + 1)
#define HDVB_T2_DELIVERY_DESCRIPTOR_SISO_MISO(d) \
        HDVB_T2_DELIVERY_SISO_MISO((d)->data[3])
#define HDVB_T2_DELIVERY_DESCRIPTOR_BANDWIDTH(d) \
        HDVB_T2_DELIVERY_BANDWIDTH((d)->data[3])
#define HDVB_T2_DELIVERY_DESCRIPTOR_GUARD_INTERVAL(d) \
        HDVB_T2_DELIVERY_GUARD_INTERVAL((d)->data[4])
#define HDVB_T2_DELIVERY_DESCRIPTOR_TRANSMISSION_MODE(d) \
        HDVB_T2_DELIVERY_TRANSMISSION_MODE((d)->data[4])
#define HDVB_T2_DELIVERY_DESCRIPTOR_OTHER_FREQUENCY(d) \
        HDVB_T2_DELIVERY_OTHER_FREQUENCY((d)->data[4])
#define HDVB_T2_DELIVERY_DESCRIPTOR_TFS(d) \
        HDVB_T2_DELIVERY_TFS((d)->data[4])

typedef struct {
    guint8 cell_id[2];
    guint8 centre_frequency[4];
} HdvbT2DeliverySimpleFrequency;

GList *
hdvb_t2_delivery_descriptor_list_simple_frequencies(
        const HdvbT2DeliveryDescriptor *desc);

G_END_DECLS

#endif /* __HDVB_SECTION_H */
